package site.ycsyxt.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import org.apache.commons.collections.CollectionUtils;

/**
 * Stream操作相关工具类
 *
 * @author ycs(15241496739 @ 163.com)
 * @date 2022/1/3
 **/
public class StreamUtils {

    /**
     * 提取对象中的某一个属性
     *
     * @param srcList 对象list
     * @param mapper  对象::get属性名
     * @param <T>     对象类型
     * @param <R>     属性类型
     * @return 属性list
     */
    public static <T, R> List<R> toList(List<T> srcList, Function<? super T, ? extends R> mapper) {
        if (CollectionUtils.isEmpty(srcList)) {
            return Lists.newArrayList();
        }
        return srcList.stream().map(mapper).collect(Collectors.toList());
    }

    /**
     * 提取对象中的某一个属性，去重
     *
     * @param srcList 对象list
     * @param mapper  对象::get属性名
     * @param <T>     对象类型
     * @param <R>     属性类型
     * @return 属性set
     */
    public static <T, R> Set<R> toSet(List<T> srcList, Function<? super T, ? extends R> mapper) {
        if (CollectionUtils.isEmpty(srcList)) {
            return Sets.newHashSet();
        }
        return srcList.stream().map(mapper).collect(Collectors.toSet());
    }

    /**
     * 构建 属性:对象  map
     *
     * @param srcList 对象list
     * @param mapper  对象::get属性名
     * @param <T>     对象类型
     * @param <K>     属性类型
     * @return 属性:对象 map
     */
    public static <T, K> Map<K, T> toMap(List<T> srcList, Function<? super T, ? extends K> mapper) {
        if (CollectionUtils.isEmpty(srcList)) {
            return new HashMap<>();
        }
        return srcList.stream().collect(Collectors.toMap(mapper, v -> v));
    }

    /**
     * 构建 属性:属性  map
     *
     * @param srcList 对象list
     * @param mapper1 对象::get属性名
     * @param mapper2 对象::get属性名
     * @param <T>     对象类型
     * @param <K>     属性类型
     * @param <U>     属性类型
     * @return 属性:属性 map
     */
    public static <T, K, U> Map<K, U> toMap(List<T> srcList,
                                            Function<? super T, ? extends K> mapper1,
                                            Function<? super T, ? extends U> mapper2) {
        if (CollectionUtils.isEmpty(srcList)) {
            return new HashMap<>();
        }
        return srcList.stream().collect(Collectors.toMap(mapper1, mapper2));
    }

    /**
     * 按特定规则筛选集合元素，返回List，过滤输入集合的null对象
     *
     * @param <T>       对象类型
     * @param source    对象集合
     * @param predicate 筛选条件
     * @return
     */
    public <T> List<T> filter(Collection<T> source, Predicate<T> predicate) {
        if (CollectionUtils.isEmpty(source)) {
            return new ArrayList<>(0);
        }
        return source.stream().filter(Objects::nonNull).filter(predicate).collect(Collectors.toList());
    }

    /**
     * 按匹配条件返回某一个对象，过滤输入集合的null对象
     *
     * @param <T>       对象类型
     * @param source    对象集合
     * @param predicate 匹配条件
     * @return
     */
    public <T> T findAny(Collection<T> source, Predicate<T> predicate) {
        if (CollectionUtils.isEmpty(source)) {
            return null;
        }
        return source.stream().filter(Objects::nonNull).filter(predicate).findAny().orElse(null);
    }

    /**
     * 判断集合是否有元素符合匹配条件
     *
     * @param <T>       对象类型
     * @param source    对象集合
     * @param predicate 匹配条件
     * @return
     */
    public <T> boolean anyMatch(Collection<T> source, Predicate<T> predicate) {
        if (CollectionUtils.isEmpty(source)) {
            return false;
        }
        return source.stream().anyMatch(predicate);
    }

    /**
     * list分组
     *
     * @param srcList   对象list
     * @param keyMapper 分组属性
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> Map<R, List<T>> groupBy(List<T> srcList, Function<? super T, ? extends R> keyMapper) {
        if (CollectionUtils.isEmpty(srcList)) {
            return new HashMap<>();
        }

        return srcList.stream().collect(Collectors.groupingBy(keyMapper));
    }

    /**
     * 切割 -> 操作 -> 归并
     *
     * @param source
     * @param maxSize
     * @param mapper
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<T> splitListConvert(final Collection<R> source, final int maxSize,
                                                  Function<List<R>, List<T>> mapper) {
        if (CollectionUtils.isEmpty(source)) {
            return new ArrayList<>(0);
        }
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize must be positive");
        }

        final int size = source.size();
        if (size <= maxSize) {
            if (source instanceof List) {
                return mapper.apply((List<R>) source);
            }
            return mapper.apply(new ArrayList<>(source));
        }

        final int step = (size + maxSize - 1) / maxSize;

        List<T> list = IntStream.range(0, step)
                .mapToObj(i -> source.stream().skip(i * maxSize).limit(maxSize).collect(Collectors.toList())).map(mapper)
                .filter(Objects::nonNull).flatMap(Collection::stream).collect(Collectors.toList());
        return list;
    }
}

